home *** CD-ROM | disk | FTP | other *** search
/ MacGames Sampler / PHT MacGames Bundle.iso / MacSource Folder / Samples from the CD / Editors / emacs / Emacs-1.14b1-sources / sources / utility-src / ispell / build.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-04  |  11.0 KB  |  578 lines  |  [TEXT/EMAC]

  1. /* Copyright (C) 1990, 1993 Free Software Foundation, Inc.
  2.  
  3.    This file is part of GNU ISPELL.
  4.  
  5.    This program is free software; you can redistribute it and/or modify
  6.    it under the terms of the GNU General Public License as published by
  7.    the Free Software Foundation; either version 2, or (at your option)
  8.    any later version.
  9.  
  10.    This program is distributed in the hope that it will be useful,
  11.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.    GNU General Public License for more details.
  14.  
  15.    You should have received a copy of the GNU General Public License
  16.    along with this program; if not, write to the Free Software
  17.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. #include <stdio.h>
  20. #include <ctype.h>
  21.  
  22. #ifdef HAVE_MALLOC_H
  23. #include <malloc.h>
  24. #endif
  25.  
  26. #include "ispell.h"
  27. #include "hash.h"
  28. #include "build.h"
  29. #include "getopt.h"
  30.  
  31. int print = 0;
  32.  
  33. #ifndef min
  34. #define min(a,b) ((a)<(b)?(a):(b))
  35. #endif
  36.  
  37.  
  38. unsigned char *tmp_hused, *hused;
  39. #define BITVECSIZE 8192        /* 64K bits */
  40. unsigned short hused_limit;
  41.  
  42. char inbuf[100];
  43. comp_char outbuf[100];
  44. struct hash_table_entry hte;
  45.  
  46. #ifdef __STDC__
  47.  
  48. unsigned short parse_flags (comp_char *, char *);
  49. hash_index find_slot (hash_index);
  50. void toomanywords (void);
  51. void mklextbl (char *, FILE *);
  52. void hash_write (FILE *);
  53. void hash_awrite (FILE *);
  54. void hash_ewrite (FILE *);
  55. int lexword (char *, int, unsigned char *);
  56. void set_bitvec (unsigned char *, unsigned short);
  57.  
  58. #else
  59.  
  60. unsigned short parse_flags (comp_char *, char *);
  61. //extern unsigned short parse_flags ();
  62. extern hash_index find_slot ();
  63. extern void toomanywords ();
  64. extern void hash_write ();
  65. extern void hash_awrite ();
  66. extern void hash_ewrite ();
  67. extern int lexword ();
  68.  
  69. #endif
  70.  
  71. int binary_flag = 0;
  72. int ascii_flag = 0;
  73. int reap_flag = 0;
  74. int debug_flag = 0;
  75.  
  76. char buildout[100];
  77.  
  78. /* this array contains letters to use when generating near misses */
  79. char near_miss_letters[256];
  80. int nnear_miss_letters;
  81.  
  82. /* this array has 1 for any character that is in near_miss_letters */
  83. char near_map[256];
  84.  
  85. int
  86. main (argc, argv)
  87.   int argc;
  88.   char **argv;
  89. {
  90.   FILE *in;
  91. #ifdef __STDC__
  92.   void reapall (void);
  93. #else
  94.   extern void reapall ();
  95. #endif
  96.   int c;
  97.   extern char *optarg;
  98.   extern int optind;
  99.   char *name;
  100.   char *freqfile = NULL;
  101.   
  102. {
  103.     // ./build -b -f freqtbl -o ispell.dict $(srcdir)/dict
  104.     char *_argv[] = { "build", "-b", "-f", "freqtbl", "-o", "ispell.dict", "./dict", 0L };
  105.     init_unix_io_driver(1,0L);
  106.     argc = sizeof(_argv) / sizeof(char *) - 1;
  107.     argv = _argv;
  108. }
  109.  
  110.   buildout[0] = 0;
  111.  
  112.   while ((c = getopt (argc, argv, "prbao:f:d")) != EOF)
  113.     {
  114.       switch (c)
  115.     {
  116.     case 'd':
  117.       debug_flag = 1;
  118.       break;
  119.     case 'f':
  120.       freqfile = optarg;
  121.       break;
  122.     case 'p':
  123.       print = 1;
  124.       break;
  125.     case 'r':
  126.       reap_flag = 1;
  127.       break;
  128.     case 'b':
  129.       binary_flag = 1;
  130.       break;
  131.     case 'a':
  132.       ascii_flag = 1;
  133.       break;
  134.     case 'o':
  135.       (void) strcpy (buildout, optarg);
  136.       break;
  137.     default:
  138.       /* message printed by getopt */
  139.       exit (1);
  140.     }
  141.     }
  142.  
  143.   if (freqfile == NULL)
  144.     {
  145.       (void) fprintf (stderr, "no freq file specified\n");
  146.       exit (1);
  147.     }
  148.   name = argv[optind];
  149.  
  150.   if (binary_flag == 0 && ascii_flag == 0)
  151.     {
  152.       (void) fprintf (stderr, "must have either -a or -b\n");
  153.       exit (1);
  154.     }
  155.  
  156.   if (debug_flag)
  157.     {
  158.       mklextbl (freqfile, stdout);
  159.       exit (0);
  160.     }
  161.  
  162.   mklextbl (freqfile, (FILE *) NULL);
  163.  
  164.   if ((in = fopen (name, "r")) == NULL)
  165.     {
  166.       (void) fprintf (stderr, "can't open %s\n", name);
  167.       exit (1);
  168.     }
  169.  
  170.   build (in);
  171.  
  172.   (void) fclose (in);
  173.  
  174.   if (reap_flag)
  175.     reapall ();
  176.  
  177.   if (binary_flag)
  178.     {
  179.       if (buildout[0] == 0)
  180.     {
  181.       strcpy (buildout, name);
  182.       strcat (buildout, ".hsh");
  183.     }
  184.       write_binary (buildout);
  185.     }
  186.  
  187.   if (ascii_flag)
  188.     {
  189.       if (buildout[0] == 0)
  190.     {
  191.       strcpy (buildout, name);
  192.       strcat (buildout, ".f");
  193.     }
  194.       write_ascii (buildout);
  195.     }
  196.   return (0);
  197. }
  198.  
  199.  
  200. void
  201. write_binary (name)
  202.   char *name;
  203. {
  204.   FILE *out;
  205.   char *mode;
  206.  
  207. #ifdef MSDOS
  208.   mode = "wb";
  209. #else
  210.   mode = "w";
  211. #endif
  212.   if ((out = fopen (name, mode)) == NULL)
  213.     {
  214.       (void) fprintf (stderr, "can't create %s\n", name);
  215.       exit (1);
  216.     }
  217.   hash_write (out);
  218.  
  219.   fclose (out);
  220. }
  221.  
  222.  
  223. void
  224. write_ascii (name)
  225.   char *name;
  226. {
  227.   FILE *out;
  228.  
  229.   if ((out = fopen (name, "w")) == NULL)
  230.     {
  231.       (void) fprintf (stderr, "can't create %s\n", name);
  232.       exit (1);
  233.     }
  234.  
  235.   hash_awrite (out);
  236.  
  237.   if (ferror (out))
  238.     {
  239.       (void) fprintf (stderr, "error writing %s\n", name);
  240.       exit (1);
  241.     }
  242.  
  243.   fclose (out);
  244. }
  245.  
  246.  
  247. void
  248. build (in)
  249.   FILE *in;
  250. {
  251.   int len;
  252.   struct hash_table_entry *htep;
  253.   unsigned short nwords = 0;
  254.   int i;
  255.   hash_index h, prev_hindex;
  256.   char *p;
  257.   unsigned short flags;
  258.   unsigned short strsize = 0;
  259. #ifdef __STDC__
  260.   unsigned short nextprime (unsigned short);
  261. #else
  262.   extern unsigned short nextprime ();
  263. #endif
  264.  
  265.   tmp_hused = (unsigned char *) xcalloc (1, BITVECSIZE);
  266.  
  267.   (void) fprintf (stderr, "Counting words: ");
  268.   while (fgets (inbuf, (int) sizeof inbuf, in) != NULL)
  269.     {
  270.       if (inbuf[0] == '#')
  271.     continue;
  272.       p = (char *) strchr (inbuf, '/');
  273.       if (p)
  274.     *p = 0;
  275.       p = (char *) strchr (inbuf, '\n');
  276.       if (p)
  277.     *p = 0;
  278.       if (inbuf[0] == 0)
  279.     continue;
  280.       if (strlen (inbuf) >= MAX_WORD_LEN)
  281.     {
  282.       (void) fprintf (stderr, "warning: %s too long\n", inbuf);
  283.       continue;
  284.     }
  285.       len = lexword (inbuf, strlen (inbuf), outbuf);
  286.       if (len == 0)
  287.     {
  288.       (void) fprintf (stderr,
  289.               "%s can't be compressed; try re-running 'freq'\n",
  290.               inbuf);
  291.       continue;
  292.     }
  293.       if (nwords >= HASH_SPECIAL - 1)
  294.     toomanywords ();
  295.       if ((nwords % 1000) == 0)
  296.     {
  297.       (void) fprintf (stderr, "%u ", nwords);
  298.       (void) fflush (stderr);
  299.     }
  300.       nwords++;
  301.       if (len > sizeof hte.u.s.data)
  302.     strsize += len - sizeof hte.u.l.data;
  303.       h = hash ((char *) outbuf);
  304.       set_bitvec (tmp_hused, h);
  305.     }
  306.   nwords++;            /* add one since slot 0 is reserved */
  307.  
  308.   (void) fprintf (stderr, "%u words\n", nwords);
  309.   hashsize = nextprime (nwords);
  310.   if (hashsize >= HASH_SPECIAL)
  311.     toomanywords ();
  312.  
  313.   hused_limit = (hashsize + 7) >> 3;
  314.   hused = (unsigned char *) xcalloc (1, hused_limit);
  315.  
  316.   /* make the slots that were introduced when rounding up
  317.      * by 8 be busy
  318.      */
  319.   for (h = hashsize; h < hused_limit * 8; h++)
  320.     set_bitvec (hused, h);
  321.   for (i = 0, h = 0; i < BITVECSIZE; i++)
  322.     {
  323.       unsigned char x = tmp_hused[i];
  324.       unsigned short bit;
  325.  
  326.       for (bit = 1; bit != 0x100; bit <<= 1, h++)
  327.     {
  328.       if (x & bit)
  329.         {
  330.           hash_index real_hash = h % hashsize;
  331.           set_bitvec (hused, real_hash);
  332.         }
  333.     }
  334.     }
  335.   /* now hused has 1 where ever something will hash to */
  336.  
  337.   free ((char *) tmp_hused);
  338.   tmp_hused = NULL;
  339.  
  340.   alloc_tables ((long) hashsize, (long) strsize);
  341.  
  342.   set_bitvec (hused, 0);
  343.   htep = (struct hash_table_entry *) xcalloc (1, sizeof *htep);
  344.   htep->next = HASH_END;
  345.   hash_store (0, htep);
  346.   free ((char *) htep);
  347.  
  348.   rewind (in);
  349.  
  350.   (void) fprintf (stderr, "Starting hash: ");
  351.   nwords = 0;
  352.   while (fgets (inbuf, (int) sizeof inbuf, in) != NULL)
  353.     {
  354.       if ((nwords % 1000) == 0)
  355.     {
  356.       (void) fprintf (stderr, "%u ", nwords);
  357.       (void) fflush (stderr);
  358.     }
  359.       nwords++;
  360.       flags = 0;
  361.       p = (char *) strchr (inbuf, '/');
  362.       if (p)
  363.     {
  364.       flags = parse_flags (inbuf, p);
  365.       *p = 0;
  366.     }
  367.       p = (char *) strchr (inbuf, '\n');
  368.       if (p)
  369.     *p = 0;
  370.       if (inbuf[0] == 0)
  371.     continue;
  372.       if (strlen (inbuf) >= MAX_WORD_LEN)
  373.     continue;
  374.       len = lexword (inbuf, strlen (inbuf), outbuf);
  375.       if (len == 0)
  376.     continue;
  377.       h = hash ((char *) outbuf) % hashsize;
  378.       if (print)
  379.     (void) printf ("%s hash %u; ", inbuf, h);
  380.       if (!hash_emptyp (h))
  381.     {
  382.       if (print)
  383.         (void) printf ("already used ");
  384.       prev_hindex = hash_find_end (h);
  385.       if (print)
  386.         (void) printf ("tail %u; ", prev_hindex);
  387.       h = find_slot (prev_hindex);
  388.       if (print)
  389.         (void) printf ("new slot %u; ", h);
  390.       hash_set_next (prev_hindex, h);
  391.     }
  392.       htep = make_hash_table_entry (outbuf, len);
  393.       hash_store (h, htep);
  394.       store_flags (h, flags);
  395.       if (print)
  396.     (void) printf ("\n");
  397.     }
  398.   (void) printf ("\n");
  399.   free ((char *) hused);
  400. }
  401.  
  402. void
  403. toomanywords ()
  404. {
  405.   (void) fprintf (stderr, "too many words, max = %u\n", HASH_SPECIAL - 1);
  406.   exit (1);
  407. }
  408.  
  409. #if 0
  410. get_bitvec (bitvec, n)
  411.      unsigned char *bitvec;
  412.      unsigned short n;
  413. {
  414.   static unsigned char bittbl[] =
  415.   {1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80};
  416.  
  417.   return (bitvec[n >> 3] & bittbl[n & 7]);
  418. }
  419.  
  420. #endif
  421.  
  422. /*
  423.  * this can return free slot that will not be used as the start of a
  424.  * hash chain.  It tries to find a slot on the same page,
  425.  * but I've not measured it to see if that helps.
  426.  */
  427. hash_index
  428. find_slot (hindex)
  429.   hash_index hindex;
  430. {
  431.   int start;
  432.   int i;
  433.   int x, bit, n;
  434.  
  435.   if (hindex >= hashsize)
  436.     {
  437.       (void) fprintf (stderr, "bad index to find_slot %x %x\n",
  438.               hindex, hashsize);
  439.       exit (1);
  440.     }
  441.   /* round down to beginning of page: 128 entries per 1K page */
  442.   start = (hindex & ~127) >> 3;
  443.   i = start;
  444.   while (1)
  445.     {
  446.       x = hused[i];
  447.       if (x != 0xff)
  448.     {
  449.       for (bit = 1, n = 0; bit < 0x100; bit <<= 1, n++)
  450.         {
  451.           if ((x & bit) == 0)
  452.         {
  453.           hused[i] |= bit;
  454.           hindex = i * 8 + n;
  455.           if (hindex >= hashsize)
  456.             {
  457.               (void) fprintf (stderr,
  458.                       "find_slot r bad %x\n",
  459.                       hindex);
  460.               exit (1);
  461.             }
  462.           return (hindex);
  463.         }
  464.         }
  465.       (void) fprintf (stderr, "hash table error\n");
  466.       exit (1);
  467.     }
  468.       i++;
  469.       if (i >= hused_limit)
  470.     i = 0;
  471.       if (i == start)
  472.     {
  473.       (void) fprintf (stderr, "hused table overflow??\n");
  474.       exit (1);
  475.     }
  476.     }
  477.   /* NOTREACHED */
  478. }
  479.  
  480. struct hash_table_entry *
  481. make_hash_table_entry (string, len)
  482.   comp_char *string;
  483.   int len;
  484. {
  485.   static struct hash_table_entry e;
  486.   comp_char *p;
  487.   int i;
  488.   e.next = HASH_END;
  489.   if (len <= sizeof e.u.s.data)
  490.     {
  491.       (void) strncpy ((char *) e.u.s.data,
  492.               (char *) string,
  493.               (int) sizeof e.u.s.data);
  494.       return (&e);
  495.     }
  496.   else
  497.     {
  498.       e.u.l.short_flag = 0;
  499.       e.u.l.len = (unsigned char) len;
  500.       p = e.u.l.data;
  501.       for (i = 0; i < sizeof e.u.l.data; i++)
  502.     *p++ = *string++;
  503.       e.u.l.sindex =
  504.     copy_out_string (string, len - sizeof e.u.l.data);
  505.       return (&e);
  506.     }
  507. }
  508.  
  509. unsigned short
  510. parse_flags (comp_char *word, char *p)
  511. {
  512.   unsigned short flags = 0;
  513.   int c;
  514.  
  515.   while (*p && *p != '\n')
  516.     {
  517.       if (*p != '/')
  518.     goto error;
  519.       c = *p++;
  520.       if (isupper (c))
  521.     c = tolower (c);
  522.  
  523.       switch (*p)
  524.     {
  525.     case 'v':
  526.       flags |= V_FLAG;
  527.       break;
  528.     case 'n':
  529.       flags |= N_FLAG;
  530.       break;
  531.     case 'x':
  532.       flags |= X_FLAG;
  533.       break;
  534.     case 'h':
  535.       flags |= H_FLAG;
  536.       break;
  537.     case 'y':
  538.       flags |= Y_FLAG;
  539.       break;
  540.     case 'g':
  541.       flags |= G_FLAG;
  542.       break;
  543.     case 'j':
  544.       flags |= J_FLAG;
  545.       break;
  546.     case 'd':
  547.       flags |= D_FLAG;
  548.       break;
  549.     case 't':
  550.       flags |= T_FLAG;
  551.       break;
  552.     case 'r':
  553.       flags |= R_FLAG;
  554.       break;
  555.     case 'z':
  556.       flags |= Z_FLAG;
  557.       break;
  558.     case 's':
  559.       flags |= S_FLAG;
  560.       break;
  561.     case 'p':
  562.       flags |= P_FLAG;
  563.       break;
  564.     case 'm':
  565.       flags |= M_FLAG;
  566.       break;
  567.     default:
  568.       goto error;
  569.     }
  570.       p++;
  571.     }
  572.   return (flags);
  573.  
  574. error:
  575.   (void) fprintf (stderr, "Syntax error: %s\n", word);
  576.   return (flags);
  577. }
  578.